package com.cw.utils.web;


import com.cw.utils.json.GsonBUILDERUtil;
import com.cw.utils.web.sensitive.SensitiveUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;


/**
 *@Author cuitong
 *@Date: 2019/3/18 10:48
 *@Email: cuitong_sl@163.com
 *@Description:  xss过滤方法类
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private final Logger logger = LoggerFactory.getLogger(XssHttpServletRequestWrapper.class);
    private HttpServletRequest request;
    private HttpServletResponse response;

    public static boolean sensitive_flag = true;

    public XssHttpServletRequestWrapper(HttpServletRequest request, HttpServletResponse response) {
        super(request);
        this.request = request;
        this.response = response;
    }
    /**
     * 参数白名单
     */
    private static final String[] getWhiteParameter = {
            "textParticulars",
            "editorValue",
            "clauseDetail",
            "contractInformation",
            "productInformation",
            "instructions",
            "graphicInformation",
            "merchantUser_agreement",
            "descraption",
            "articleDetails",
            "protocolModel",
            "donationParticulars",
            "informContent",
            "projectRecharge",
            "protocolContent"
    };

    /**
     * 动态富文本参数白名单
     */
    private static final String[] getDTWhiteParameter = {
            "DTFWBXSS_"
    };
    /**
     * 富文本url名单
     *  富文本图片上传会报未找到上传数据的错误需要单独处理
     */
    private static final String[] getUeditorUrl = {"donationBusiness/add",
            "donationBusiness/edit",
            "insuranceCompany/insuranceClauseAdd",
            "insuranceCompany/insuranceClauseEdit",
            "insuranceCompany/insuranceCoverageRelationAdd",
            "insuranceCompany/insuranceCoverageRelationEdit",
            "contract/contractProductAdd",
            "contract/contractProductEdit",
            "insuranceProduct/insuranceProductAdd",
            "insuranceProduct/insuranceProductEdit",
            "productBaseInfo/add",
            "productBaseInfo/edit",
            "productSku/add",
            "productSku/edit",
            "merchantUser/merchantUser_add",
            "merchantUser/merchantUser_edit",
            "productSkuImport/productBaseInfoImport",
            "productExamTicketsDefinition/add_do",
            "productExamTicketsDefinition/update_do",
            "picArticleInfo/addPic_do",
            "picArticleInfo/updatePic_do",
            "picArticleInfo/addText_do",
            "picArticleInfo/updateText_do",
            "picArticleInfo/addPic_do",
            "picArticleInfo/updatePic_do",
            "transProject/add",
            "transProject/edit",
            "donationProject/add",
            "donationProject/edit",
            "progressManage/add",
            "progressManage/edit",
            "projectDisclosure/add",
            "projectDisclosure/edit",
            "transBusiness/add",
            "transBusiness/edit",
            "foundationInfo/add",
            "foundationInfo/edit",
            "productSkuImport/productBaseInfoImport",
            "productSkuImport/productSkuImport",
            "productSkuImport/productSkuEditImport",
            "cashierDesk/addCashierDesk",
            "cashierDesk/userInfoMessageAdd",
            "nonTaxManage/editNonTaxSendManage",
            "nonTaxManage/nonTaxManageAdd",
            "rechMer/add",
            "rechMer/edit",
            "fsConsumerContract/addFsConsumerContract_do",
            "fsConsumerContract/updateFsConsumerContract_do",
            "greenChannelProtocol/addGreenChannelProtocol",
            "greenChannelProtocol/editGreenChannelProtocol"
    };

    /*
     * @Author 陈伟
     * @Date 2021/3/16 15:55
     * @description 动态富文本url名单
     * @param: null
     * @Return
     */
    private static final String[] getDTUeditorUrl = {
            "userInfoImport/userInfoUpdate",
            "userInfoImport/userInfoAdd",
            "cashierDesk/addCashierDesk",
            "cashierDesk/userInfoMessageAdd",
            "merchantSchoolStatusInfo/add",
            "merchantSchoolStatusInfo/edit",
            "productUserInfoDetails/productEditUserInfoDetails",
            "taskStatistics/updateMerchantStaffExtendsInfo"
    };

    /**
     * 不需要违禁词过滤的页面
     */
    public static String[] sensitiveWhiteListURL = {
            //自己在后台方法处理违禁词
            "billDetail/addBillDetail.do",
            "billDetail/importBillExeclNew.do"
    };

    private boolean checkSensitiveWord(String value){
        if(!sensitive_flag){
            return false;
        }
        String url = getUrl(request);
        //违禁词白名单
        for(String whiteURL:sensitiveWhiteListURL){
            if(url.contains(whiteURL.toLowerCase())){
                return false;
            }
        }
        //存在违禁词，返回true
        return SensitiveUtil.checkSensitiveWord(value);
    }

    private Set<String> getSensitiveWord(String value){
        return SensitiveUtil.getSensitiveWord(value);
    }

    @Override
    public String getHeader(String name) {
        if("Origin".equals(name)){
            return super.getHeader(name);
        }
        if(!XssCommonUtils.stripXssOtherBoolean(name,XssCommonUtils.xss_mer)){
            writeJson(response);
        }
        String value = super.getHeader(name);
        if (value != null)
        {
            value = XssCommonUtils.stripXss(value,XssCommonUtils.xss_mer);
            if(!XssCommonUtils.stripXssOtherBoolean(value,XssCommonUtils.xss_mer)){
                writeJson(response);
            }
        }
        return value;
    }

    @Override
    public String getQueryString() {
        String value = super.getQueryString();
        if (value != null)
        {
//            try{
               value = XssCommonUtils.stripXss(value,XssCommonUtils.xss_mer);
               if(!XssCommonUtils.stripXssOtherBoolean(value,XssCommonUtils.xss_mer)){
                   writeJson(response);
                   return "";
               }
               if(checkSensitiveWord(value)){
                   Set<String> result = getSensitiveWord(value);
                   writeJson2(response,result);
                   return "";
               }
//             } catch(Exception e){
//                 logger.error("XssCommonUtils-请求参数有非法入参", e);
//                 writeJson(response);
//            }
        }
        return value;
    }

    @Override
    public String getParameter(String name) {
        String values = super.getParameter(name);
        if(values != null) {
            String escapseValues = null;
            if (StringUtils.isNotEmpty(values)){
                //获取url链接参数
                String url = getUrl(request);
                //静态富文本
                for (String whiteUrl : getUeditorUrl) {
                    if (url.contains(whiteUrl.toLowerCase())){
                        for (String white : getWhiteParameter) {
                            if (white.equals(name)){
                                escapseValues = XssCommonUtils.stripXssByUeditor(values);
                                return escapseValues;
                            }
                        }
                    }
                }
                //动态富文本
                for (String whiteUrl : getDTUeditorUrl) {
                    if (url.contains(whiteUrl.toLowerCase())){
                        for (String white : getDTWhiteParameter) {
                            if(name.length()>9) {
                                String qzName = name.substring(0, 9);
                                if (white.equals(qzName)) {
                                    escapseValues = XssCommonUtils.stripXssByUeditor(values);
                                    return escapseValues;
                                }
                            }
                        }
                    }
                }
                if (values != null){
                    escapseValues = values;
                    escapseValues = XssCommonUtils.stripXss(escapseValues,XssCommonUtils.xss_mer);
                    if(!XssCommonUtils.stripXssOtherBoolean(escapseValues,XssCommonUtils.xss_mer)){
                        writeJson(response);
                        return "";
                    }

                    if(checkSensitiveWord(escapseValues)){
                        Set<String> result = getSensitiveWord(escapseValues);
                        writeJson2(response,result);
                        return "";
                    }
                }
            }else {
                escapseValues = values;
            }
            return escapseValues;
        }
        return values;
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        // if("rows".equals(name)){
        //     if(values != null && values.length>0) {
        //         String data_rows = Config.getString("data_rows");
        //         if(StringUtils.isBlank(data_rows)){
        //             data_rows = "2000";
        //         }
        //         int rows = Integer.valueOf(values[0]);
        //         if(rows>Integer.valueOf(data_rows)){
        //             values[0] = data_rows;
        //         }
        //     }
        // }
        if(values != null) {
            int length = values.length;
            String[] escapseValues = new String[length];
            for(int i = 0; i < length; i++){
                if (StringUtils.isNotEmpty(values[i])){
                    //获取url链接参数
                    String url = getUrl(request);
                    for (String whiteUrl : getUeditorUrl) {
                        if (url.contains(whiteUrl.toLowerCase())){
                            for (String white : getWhiteParameter) {
                                if (white.equals(name)){
                                    escapseValues[i] = XssCommonUtils.stripXssByUeditor(values[i]);
                                    return escapseValues;
                                }
                            }
                        }
                    }
                    //动态富文本
                for (String whiteUrl : getDTUeditorUrl) {
                    if (url.contains(whiteUrl.toLowerCase())){
                        for (String white : getDTWhiteParameter) {
                            if(name.length()>9) {
                                String qzName = name.substring(0, 9);
                                if (white.equals(qzName)) {
                                    escapseValues[i] = XssCommonUtils.stripXssByUeditor(values[i]);
                                    return escapseValues;
                                }
                            }
                        }
                    }
                }
                    if (values[i] != null){
                        escapseValues[i] = values[i];
                        escapseValues[i] = XssCommonUtils.stripXss(escapseValues[i],XssCommonUtils.xss_mer);
                        if(!XssCommonUtils.stripXssOtherBoolean(escapseValues[i],XssCommonUtils.xss_mer)){
                            writeJson(response);
                            return new String[length];
                        }

                        if(checkSensitiveWord(escapseValues[i])){
                            Set<String> result = getSensitiveWord(escapseValues[i]);
                            writeJson2(response,result);
                            return new String[length];
                        }
                    }
                }else {
                    escapseValues[i] = values[i];
                }
            }
            return escapseValues;
        }
        return super.getParameterValues(name);
    }

    public String getUrl(HttpServletRequest request){
        String requestURI = request.getRequestURI();
        String contextPath = request.getContextPath();
        String urlWithOutContextPath = requestURI.substring(contextPath.length()).toLowerCase();
        return urlWithOutContextPath;
    }
    /**
     * 输出JSON
     *
     * @param response
     */
    protected void writeJson(HttpServletResponse response) {
        PrintWriter out = null;
        try {
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.setContentType("application/json; charset=utf-8");
            //设置状态码,设置为405
            response.setStatus(200);
            out = response.getWriter();
            Map<String, Object> returnMap = new HashMap<>();
//            returnMap.put("type", ErrorEnum.ERROR_MOBILE_10002.getReturntype());
//            returnMap.put("code", ErrorEnum.ERROR_MOBILE_10002.getReturncode());
            returnMap.put("message", "很抱歉，由于您访问的URL有可能对网站造成安全威胁（XSS攻击），您的访问被阻断。");
            out.write(GsonBUILDERUtil.GSON_BUILDER_COMMON.toJson(returnMap));//NOSONAR
        } catch (IOException e) {
            logger.error("",e);
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }


    /**
     * 输出JSON
     *
     * @param response
     */
    protected void writeJson2(HttpServletResponse response, Set<String> msg) {
        PrintWriter out = null;
        try {
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.setContentType("application/json; charset=utf-8");
            //设置状态码,设置为200（为了让报错信息，在页面弹窗提示）
            response.setStatus(200);
            out = response.getWriter();
            Map<String, Object> returnMap = new HashMap<>();
//            returnMap.put("type", ErrorEnum.ERROR_MOBILE_10002.getReturntype());
//            returnMap.put("code", ErrorEnum.ERROR_MOBILE_10002.getReturncode());
            returnMap.put("message", "填写内容中包含"+msg+"，无法成功保存");
            out.write(GsonBUILDERUtil.GSON_BUILDER_COMMON.toJson(returnMap));//NOSONAR
        } catch (IOException e) {
            logger.error("",e);
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }
}

